# -*- coding: utf-8 -*-
from Exceptions.LibraryException import LibraryException
from MediaCollection.Database import Database

"""
Die Film-Klasse repräsentiert einen Film mit allen in der Datenbank 
gespeicherten Attributen. Über ein Objekt dieser Klasse können neue Einträge in 
die Datenbank eingefügt werden, im Gegenzug aber auch über die Id des Eintrags
in der Datenbank die entsprechenden Informationen in das Objekt eingelesen 
werden.

@author: Philipp Dermitzel
@date: 2011-04-08
@version: 1.0.0
@attention: Da ein Großteil der Videodateien nicht über Metadaten verfügt,
    muss zumindest der Name des Filmes über den Dateinamen bzw. den Pfad 
    ableitbar sein. Ohne diese Voraussetzung können die Filmdaten nicht korrekt
    eingelesen werden. Es wird eine der folgende Strukturierungen empfohlen:
        Filme/<Filmname>/Datei.<Dateiendung>
        Filme/<Filmname>.<Dateiendung>
    Bei Serien sollte eine der folgenden Strukturierungen eingehalten werden:
        Serien/<Serienname>/<Staffelnr>/<Episodennummer>.<Dateiendung>
    Ein (gutes) Beispiel wäre der folgende Baum:
        | Filme
        |--| Taxi_Driver
        |--|--| taxidriver.avi
        |--| Star_Wars_IV
        |--|--| sw4.avi
        | Serien
        |--| Breaking_Bad
        |--|--| Season_1
        |--|--|--| 01.avi
        |--|--|--| 02.avi       
"""
class Film(object):
    
    """
    ----------------------------------------------------------------------------
    Konstruktor
    ----------------------------------------------------------------------------
    """
    def __init__(self, id = None):
        """
        Speichert alle Informationen des Films. Ist über C(getData()) abrufbar.
        @type: Dictionary
        """
        self.__filmData = {
            'id' : None,
            'name' : None,
            'sort' : None,
            'movie' : None,
            'length' : None,
            'year' : None,
            'path' : None,
            'imgPath' : None,
            'imdbId' : None
        }
        
        if id is not None:
            self.__filmData['id'] = id
            self.getDataFromDb()
        
    """
    ----------------------------------------------------------------------------
    Getter und Setter
    ----------------------------------------------------------------------------
    """
    
    """
    Setzt die Attribute des Films um diesen später erfolgreich in die 
    Datenbank einfügen zu können. Dafür sollte das übergebene Dictionary
    C(dataDict) alle eben dort beschriebenen Informationen enthalten.    
    @param dataDict: Alle benötigten Informationen zum Film. Die momentan 
        genutzten Felder sind: id, name, sort, movie (Film[True] oder 
        Serie[False], length, year, path, imgPath (Der Pfad zu dem Bild für
        den Film und imdbId (die imdb-Id).
    @type dataDict: Dictionary
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Film
    """
    def setData(self, dataDict):
        if 'id' in dataDict:
            self.__filmData['id'] = dataDict['id']
        if 'name' in dataDict:
            self.__filmData['name'] = dataDict['name']
        if 'sort' in dataDict:
            self.__filmData['sort'] = dataDict['sort']
        if 'movie' in dataDict:
            self.__filmData['movie'] = dataDict['movie']
        if 'length' in dataDict:
            self.__filmData['length'] = dataDict['length']
        if 'year' in dataDict:
            self.__filmData['year'] = dataDict['year']
        if 'path' in dataDict:
            self.__filmData['path'] = dataDict['path']
        if 'imgPath' in dataDict:
            self.__filmData['imgPath'] = dataDict['imgPath']
        if 'imdbId' in dataDict:
            self.__filmData['imdbId'] = dataDict['imdbId']
        return self
    
    """
    Setzt ein einzelnen Attribut des Films. Die momentan genutzten Felder sind:
    id, name, sort, movie (Film[True] oder Serie[False], length, year, path, 
    imgPath (Der Pfad zu dem Bild für den Film und imdbId (die imdb-Id).
    @param key: Der Schlüssel.
    @type key: String
    @param value: Der zu setzende Wert.
    @type value: int oder String
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Film
    """
    def setValue(self, key, value):
        if key == "id":
            self.__filmData['id'] = value
        elif key == "name":
            self.__filmData['name'] = value
        elif key == "sort":
            self.__filmData['sort'] = value
        elif key == "movie":
            self.__filmData['movie'] = value
        elif key == "length":
            self.__filmData['length'] = value
        elif key == "year":
            self.__filmData['year'] = value
        elif key == "path":
            self.__filmData['path'] = value
        elif key == "imgPath":
            self.__filmData['imgPath'] = value
        elif key == "imdbId":
            self.__filmData['imdbId'] = value
        else: 
            raise LibraryException("\"%s\" ist kein valider Parameter" %key)
        return self
    
    """
    Getter
    @return: Alle Film-Daten.
    @rtype: Dictionary
    """
    def getData(self):
        return self.__filmData
    
    """
    Getter.
    @return: Die ID des Films in der Datenbank.
    @rtype: int
    """
    def getId(self):
        return self.__filmData['id']
    
    """
    Getter.
    @return: Der Name des Films.
    @rtype: String
    """
    def getName(self):
        return self.__filmData['name']
    
    """
    Getter.
    @return: Die Sortierungsschreibweise des Films.
    @rtype: String
    """
    def getSort(self):
        return self.__filmData['sort']
    
    """
    Getter.
    @return: Film [True] oder Serie [False]
    @rtype: boolean
    """
    def isMovie(self):
        return self.__filmData['movie']
    
    """
    Getter.
    @return: Die Länge des Films in der Datenbank in Sekunden.
    @rtype: int
    """
    def getLength(self):
        return self.__filmData['length']
    
    """
    Getter.
    @return: Das Erscheinungsjahr des Films in der Datenbank.
    @rtype: int
    """
    def getYear(self):
        return self.__filmData['year']
    
    """
    Getter.
    @return: Der Pfad zur Filmdatei.
    @rtype: String
    """
    def getPath(self):
        return self.__filmData['path']
        
    """
    Getter.
    @return: Der Pfad zum Bild für diesen Film.
    @rtype: String
    """
    def getImgPath(self):
        return self.__filmData['imgPath']
     
    """
    Getter.
    @return: Die imdb-Id des Films.
    @rtype: String
    """
    def getImdbId(self):
        return self.__filmData['imdbId']
    
    """
    ----------------------------------------------------------------------------
    Methoden der Klasse
    ----------------------------------------------------------------------------
    """ 
    
    """
    Liest die Film-Daten aus der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Film
    """
    def getDataFromDb(self):
        db = Database()
        if self.__filmData['id'] is None:
            raise LibraryException('Keine ID übergeben')
        
        try: 
            db.select('*', 'Film', {'id':self.__filmData['id']})
            curFilm = db.dbCursor.fetchone()
            self.__filmData['id'] = curFilm[0]
            self.__filmData['name'] = curFilm[1]
            self.__filmData['sort'] = curFilm[2]
            self.__filmData['movie'] = curFilm[3]
            self.__filmData['length'] = curFilm[4]
            self.__filmData['year'] = curFilm[5]
            self.__filmData['path'] = curFilm[6]
            self.__filmData['imgPath'] = curFilm[7]
            self.__filmData['imdbId'] = curFilm[8]
        except: raise LibraryException('Film nicht vorhanden')        
        return self
    
    """
    Speichert die Film-Daten in der Datenbank.
    @param getData: Dieser Parameter ist für die Kind-Klasse C(Episode) gedacht,
        damit diese die eigenen Daten in die Datenbank schreiben kann, bevor
        die Methode C(getDataFromDb()) aufgerufen wird. Diese ruft dann die 
        Kind-Klasse selbst auf und holt so alle benötigten Daten.
    @type getData: Boolean
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Film
    """   
    def insertIntoDb(self, getData = True):
        if (self.__filmData['path'] is not None
        and self.__filmData['length'] is not None):
            db = Database()
            db.savepoint("sp")
            try: 
                db.insert('Film', {
                    'name'      : self.__filmData['name'],
                    'sort'      : self.__filmData['sort'],
                    'movie'      : self.__filmData['movie'],
                    'length'      : self.__filmData['length'],
                    'year'      : self.__filmData['year'],
                    'path'      : self.__filmData['path'],
                    'imgPath'   : self.__filmData['imgPath'],
                    'imdbId'      : self.__filmData['imdbId']
                })
                self.__filmData['id'] = db.dbCursor.lastrowid
                if getData: self.getDataFromDb()
            except:
                db.rollback("sp")
                raise LibraryException('Konnte Daten nicht einfügen')
        else: raise LibraryException('Nicht alle Daten vorhanden')
        return self
    
    """
    Löscht einen Film aus der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Film
    """    
    def deleteFromDb(self):
        if self.__filmData['id'] is None:
            self.getDataFromDb()
        db = Database()        
        try: 
            db.delete('Film', {'id':self.__filmData['id']})
        except: raise LibraryException('Film nicht vorhanden')
        return self
    
    """
    Holt alle Filme aus der Datenbank. Die Sortierungs-Reihenfolge kann über 
    den Parameter orderBy angegeben werden. Dabei kann dieser allen Attributen 
    eines C(Film)-Objektes entsprechen.
    @param orderBy: Sortieren nach x.
    @type orderBy: String
    @return: Ein Array mit allen Filmen als Film-Objekte.
    @rtype: Array
    """
    def getAllFilms(self, orderBy = 'name'):
        db = Database()
        try:
            db.select('id', 'Film', {}, "ORDER BY %s" %(orderBy))
            allFilms = db.dbCursor.fetchall()
            filmArray = []
            for film in allFilms: 
                curFilm = Film(int(film[0]))
                curFilm.getDataFromDb()
                filmArray.append(curFilm)
            return filmArray
        except: raise LibraryException('Konnte die Filme nicht auslesen')